﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Notoric.ViewModel.Elements.CWNotation
{
    /// <summary>
    /// Defines extension methods for collections of <see cref="CoreSymbol"/>s.
    /// </summary>
    public static class Extensions
    {
        /// <summary>
        /// Groups the collection of core symbols by part to which the symbols belong.
        /// </summary>
        /// <param name="source">
        /// <para>
        /// Type: <see cref="IEnumerable{T}"/> of <see cref="Notoric.ViewModel.Elements.CWNotation.CoreSymbol"/>
        /// </para>
        /// <para>
        /// The source collection.
        /// </para>
        /// </param>
        /// <returns>
        /// <para>
        /// Type: <see cref="IEnumerable{T}"/> of <see cref="PartGroup"/>
        /// </para>
        /// <para>
        /// The collection of part groups.
        /// </para>
        /// </returns>
        public static IEnumerable<PartGroup> GroupByPart(this IEnumerable<CoreSymbol> source)
        {
            if (source == null)
                throw new ArgumentNullException("source");

            return from symbol in source
                   group symbol by ((Model.Elements.CWNotation.Staff)symbol.FindOwner<Staff>().AdaptedElement).Descriptor.FindOwner<Model.Elements.PartDescriptorElement>() into g
                   select new PartGroup(g);
        }

        /// <summary>
        /// Orders the collection of core symbols by beat at which the symbols begin.
        /// </summary>
        /// <param name="source">
        /// <para>
        /// Type: <see cref="IEnumerable{T}"/> of <see cref="Notoric.ViewModel.Elements.CWNotation.CoreSymbol"/>
        /// </para>
        /// <para>
        /// The source collection.
        /// </para>
        /// </param>
        /// <returns>
        /// <para>
        /// Type: <see cref="IEnumerable{T}"/> of <see cref="CoreSymbol"/>
        /// </para>
        /// <para>
        /// The ordered collection.
        /// </para>
        /// </returns>
        public static IEnumerable<CoreSymbol> OrderByBeat(this IEnumerable<CoreSymbol> source)
        {
            return from symbol in source
                   orderby ((Model.Elements.CWNotation.CoreSymbol)symbol.AdaptedElement).Measure.Number ascending,
                           ((Model.Elements.CWNotation.CoreSymbol)symbol.AdaptedElement).Beat.Beginning ascending
                   select symbol;
        }
    }

    /// <summary>
    /// Holds one part group.
    /// </summary>
    public class PartGroup
    {
        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="PartGroup"/> class.
        /// </summary>
        /// <param name="partName">Name of the part.</param>
        /// <param name="symbols">
        /// <para>
        /// Type: <see cref="IEnumerable{T}"/> of <see cref="Notoric.ViewModel.Elements.CWNotation.CoreSymbol"/>
        /// </para>
        /// <para>
        /// The symbols of the part.
        /// </para>
        /// </param>
        public PartGroup(string partName, IEnumerable<CoreSymbol> symbols)
        {
            PartName = partName;
            Symbols = symbols;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="PartGroup"/> class.
        /// </summary>
        /// <param name="g">
        /// <para>
        /// Type: <see cref="IGrouping{T1, T2}"/> of <see cref="Notoric.Model.Elements.PartDescriptorElement"/> and <see cref="Notoric.ViewModel.Elements.CWNotation.CoreSymbol"/>
        /// </para>
        /// <para>
        /// The grouping instance containing the data of the group.
        /// </para></param>
        public PartGroup(IGrouping<Model.Elements.PartDescriptorElement, CoreSymbol> g)
        {
            PartName = g.Key.Name;
            Symbols = g;
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets the name of the part.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="String"/>
        /// </para>
        /// <para>
        /// The name of the part.
        /// </para>
        /// </value>
        public string PartName
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the symbols belonging to the part.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="IEnumerable{T}"/> of <see cref="CoreSymbol"/>
        /// </para>
        /// <para>
        /// The symbols of the part.
        /// </para>
        /// </value>
        public IEnumerable<CoreSymbol> Symbols
        {
            get;
            private set;
        }

        #endregion
    }
}
